package cn.thread.pool.dynamic.thread.pool.sdk.config;

import cn.thread.pool.dynamic.thread.pool.sdk.domain.DynamicThreadPoolService;
import cn.thread.pool.dynamic.thread.pool.sdk.domain.IDynamicThreadPoolService;
import cn.thread.pool.dynamic.thread.pool.sdk.domain.model.entity.ThreadPoolConfigEntity;
import cn.thread.pool.dynamic.thread.pool.sdk.domain.model.valobj.RegistryEnumVO;
import cn.thread.pool.dynamic.thread.pool.sdk.register.Iregister;
import cn.thread.pool.dynamic.thread.pool.sdk.register.redis.redisRegister;
import cn.thread.pool.dynamic.thread.pool.sdk.trigger.job.redisRegisterJob;
import cn.thread.pool.dynamic.thread.pool.sdk.trigger.listen.redisListen;
import org.apache.commons.lang.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;


/**
 * @author: xiaoxie
 * create: 2025-02-09 17:38
 * @BelongsProject: custom-dynamic-thread-pool
 * @BelongsPackage: cn.thread.pool.dynamic.thread.pool.sdk.config
 * description: 自动配置
 */
@Configuration
@EnableConfigurationProperties(DynamicThreadPoolRedisProperties.class)
@EnableScheduling
public class DynamicThreadPoolAutoConfig {
    private final Logger logger = LoggerFactory.getLogger(DynamicThreadPoolAutoConfig.class);

    private  String applicationName;
    @Bean("dynamicThreadPollService")
    public IDynamicThreadPoolService dynamicThreadPollService(ApplicationContext applicationContext
                                          , Map<String,ThreadPoolExecutor> threadPoolExecutorMap,RedissonClient redissonClient) {
        applicationName = applicationContext.getEnvironment().getProperty("spring.application.name");
        if (StringUtils.isBlank(applicationName)) {
            applicationName = "缺省的";
            logger.warn("动态线程池，启动提示。SpringBoot 应用未配置 spring.application.name 无法获取到应用名称！");
        }
        // 获取缓存数据，设置本地线程池配置
        Set<String> threadPoolKeys = threadPoolExecutorMap.keySet();
        for (String threadPoolKey : threadPoolKeys) {
            ThreadPoolConfigEntity threadPoolConfigEntity = redissonClient.<ThreadPoolConfigEntity>getBucket(RegistryEnumVO.THREAD_POOL_CONFIG_PARAMETER_LIST_KEY.getKey() + "_" + applicationName + "_" + threadPoolKey).get();
            if (null == threadPoolConfigEntity) {
                continue;
            }
            ThreadPoolExecutor threadPoolExecutor = threadPoolExecutorMap.get(threadPoolKey);
            if(0 == threadPoolConfigEntity.getCorePoolSize() || 0 == threadPoolConfigEntity.getMaximumPoolSize()) {
                break;
            }
            threadPoolExecutor.setCorePoolSize(threadPoolConfigEntity.getCorePoolSize());
            threadPoolExecutor.setMaximumPoolSize(threadPoolConfigEntity.getMaximumPoolSize());
        }


        return new DynamicThreadPoolService(applicationName, threadPoolExecutorMap);
    }

    /**
     *  自动加载redis配置
     * @param properties
     * @return
     */
    @Bean("dynamicThreadRedissonClient")
    public RedissonClient redisRedissonClient(DynamicThreadPoolRedisProperties properties) {
           Config config = new Config();
            // 根据需要可以设定编解码器；https://github.com/redisson/redisson/wiki/4.-%E6%95%B0%E6%8D%AE%E5%BA%8F%E5%88%97%E5%8C%96
            config.setCodec(JsonJacksonCodec.INSTANCE);

            config.useSingleServer()
                    .setAddress("redis://" + properties.getHost() + ":" + properties.getPort())
                    .setPassword(properties.getPassword())
                    .setConnectionPoolSize(properties.getPoolSize())
                    .setConnectionMinimumIdleSize(properties.getMinIdleSize())
                    .setIdleConnectionTimeout(properties.getIdleTimeout())
                    .setConnectTimeout(properties.getConnectTimeout())
                    .setRetryAttempts(properties.getRetryAttempts())
                    .setRetryInterval(properties.getRetryInterval())
                    .setPingConnectionInterval(properties.getPingInterval())
                    .setKeepAlive(properties.isKeepAlive())
            ;

            RedissonClient redissonClient = Redisson.create(config);

            logger.info("动态线程池，注册器（redis）链接初始化完成。{} {} {}", properties.getHost(), properties.getPoolSize(), !redissonClient.isShutdown());

            return redissonClient;
        }

    /**
     *  实例化 redis注册中心
     * @param redissonClient
     * @return
     */
    @Bean
        public Iregister redisRegister(RedissonClient redissonClient) {
              return new redisRegister(redissonClient);
        }

        @Bean("redisRegisterJob")
        public redisRegisterJob registerJob(IDynamicThreadPoolService service,Iregister redisRegister) {

           return new redisRegisterJob(service,redisRegister);
        }
        @Bean
        public redisListen redisListen(IDynamicThreadPoolService service,Iregister redisRegister) {
           return new redisListen(service,redisRegister);
        }

        @Bean(name = "dynamicThreadPoolRedisTopic")
        public RTopic redisTopic(redisListen redisListen,RedissonClient redissonClient) {
            RTopic rTopic = redissonClient.getTopic(RegistryEnumVO.DYNAMIC_THREAD_POOL_REDIS_TOPIC.getKey() + "_" + applicationName);
            rTopic.addListener(ThreadPoolConfigEntity.class,redisListen);
            return rTopic;
        }

    }
